#define LOW_LEVEL_SCANNER       my_scanner_routine
#define PEEK_BUFFER_SIZE        128

short my_scanner_routine ( void );

typedef struct 
_peek {
        int     buffer [ PEEK_BUFFER_SIZE ],
                base, 
                first,
                last;
} peek_t;

peek_t   Peek;


// --------------------------------------------------------------------
// usual scan function
// --------------------------------------------------------------------

short
get_token ( void )                                  
{
    short   token;

    if ( Peek.first ) {                                // peek buffer not empty
        token = Peek.buffer [ Peek.first ];
        ++Peek.base;
        ++Peek.first;
        if ( Peek.first > Peek.last ) {                // peek buffer now empty
            Peek.base  = 0;
            Peek.first = 0;
        }
    } else {                                              // peek buffer empty
        token = LOW_LEVEL_SCANNER ();
    }

    return  token;
}


// --------------------------------------------------------------------
// scan next token without consuming it
//
// Note that peeking always happens in order and with no intervening
// scans. So if peek(3) is called, it is certain that peek(1), peek(2)
// preceeded it. The base is needed because it is not guaranteed that
// the peek buffer will be emptied by scans before another set of
// peeks occurs. (See the test cases below.) So the peek base slides
// to the right until the buffer is emptied. 
//
// --------------------------------------------------------------------

short
peek_token ( int   level )
{
    short   token;

    if ( Peek.first ) {                                // peek buffer not empty
        if ( level > Peek.last - Peek.base ) {
            ++Peek.last;
            Peek.buffer [ Peek.last ] = LOW_LEVEL_SCANNER ();
        } 
    } else {                                           // peek buffer empty
        Peek.base  = 0;
        Peek.first = 1;
        Peek.last  = 1;
        Peek.buffer [ 1 ] = LOW_LEVEL_SCANNER ();
    }

    token = Peek.buffer [ Peek.base + level ];

    return  token;
}


// --------------------------------------------------------------------
// test driver
// 
// The scanner returns 1, 2, 3,... , so peek(1) should always be 
// the last get() + 1. The get()'s must be in order 1, 2, 3,... 
// 
// --------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>

short
my_scanner_routine ( void )
{
    static
    short   token = 0;

    return  ++token;
}


int
main ( int     argc,
       char   *argv[] )
{
    int   level;

    level = 1;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );
    level = 2;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );
    level = 3;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );

    printf ( "get () = %d \n", get_token () );

    level = 1;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );
    level = 2;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );
    level = 3;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );

    printf ( "get () = %d \n", get_token () );
    printf ( "get () = %d \n", get_token () );

    level = 1;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );
    level = 2;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );
    level = 3;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );

    printf ( "get () = %d \n", get_token () );
    printf ( "get () = %d \n", get_token () );
    printf ( "get () = %d \n", get_token () );
    printf ( "get () = %d \n", get_token () );

    level = 1;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );
    level = 2;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );
    level = 3;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );

    printf ( "get () = %d \n", get_token () );
    printf ( "get () = %d \n", get_token () );
    printf ( "get () = %d \n", get_token () );

    level = 1;
    printf ( "peek ( %d ) = %d \n", level, peek_token ( level ) );

    printf ( "get () = %d \n", get_token () );
    printf ( "get () = %d \n", get_token () );

    return 0;
}